﻿//  Copyright (c) 2010 Ray Liang (http://www.dotnetage.com)
//  Dual licensed under the MIT and GPL licenses:
//  http://www.opensource.org/licenses/mit-license.php
//  http://www.gnu.org/licenses/gpl.html

using System;
using System.Web;
using System.Web.Mvc;
using System.Xml;
using DNA.OpenAPI.Rsd;
using System.Net;
using System.Collections.Generic;
using System.Linq;

namespace DNA.Mvc.Publishing.Controllers
{
    /// <summary>
    /// The Controller provides the OpenAPI function
    /// </summary>
    public class OpenAPIController : Controller
    {
        private WebSiteContext _context;
        private IPubContext pubContext;

        public OpenAPIController(WebSiteContext context,IPubContext pubcontext) 
        {
            _context = context;
            pubContext = pubcontext;
        }

        public ActionResult Rsd()
        {
            var web = _context.Web;// this.CurrentWeb();
            var root = _context.RootWeb;// WebSite.Open();
            var url = UrlResolver.Resolve(HttpContext, root);
            var doc = new RsdDoc()
            {
                Service = new RsdService()
                {
                    EngineLink =url,
                    HomePageLink = url
                }
            };
            
            string xmlrpcUrl = url + Url.Content("~/xmlrpc.metaweblog");
            
            doc.Service.RsdAPIs.Add(new RsdAPI()
            {
                BlogID = web.Name,
                Link = xmlrpcUrl,
                Name = "WordPress",
                Preferred = false,
            });

            doc.Service.RsdAPIs.Add(new RsdAPI()
            {
                BlogID = web.Name,
                Link = xmlrpcUrl,
                Name = "Movable Type",
                Preferred = false,
            });

            doc.Service.RsdAPIs.Add(new RsdAPI()
            {
                BlogID = web.Name,
                Link = xmlrpcUrl,
                Name = "MetaWeblog",
                Preferred = true,
            });

            doc.Service.RsdAPIs.Add(new RsdAPI()
            {
                BlogID = web.Name,
                Link = xmlrpcUrl,
                Name = "Blogger",
                Preferred = false,
            });

            //TODO: Add atom publishing protocol.
            var xmlDoc = DNA.Utility.XmlSerializerUtility.SerializeToXml(typeof(RsdDoc), doc);
            return Content(xmlDoc, "text/xml");
        }

        public ActionResult WlWManifest()
        {
            string baseUrl = ControllerContext.RequestContext.HttpContext.Request.Url.Scheme + "://" + ControllerContext.RequestContext.HttpContext.Request.Url.Authority;
            var web = _context.Web;// this.CurrentWeb();
            var xmlDoc = new XmlDocument();
            xmlDoc.Load(HttpContext.Server.MapPath("~/wlwmanifest.xml"));
            var mgr = new XmlNamespaceManager(xmlDoc.NameTable);
            mgr.AddNamespace("n1", "http://schemas.microsoft.com/wlw/manifest/weblog");
            var pageEditUrlNode = xmlDoc.SelectSingleNode("//n1:postEditingUrl", mgr);
            var adminUrlNode = xmlDoc.SelectSingleNode("//n1:adminUrl", mgr);
            var webLayoutNode = xmlDoc.SelectSingleNode("//n1:view[@type='WebLayout']", mgr);
            var webPreviewNode = xmlDoc.SelectSingleNode("//n1:view[@type='WebPreview']", mgr);

            pageEditUrlNode.InnerXml = "<![CDATA[" + baseUrl + ControllerContext.HttpContext.Server.UrlDecode(Url.Action("Trackback", new { Area = "", id = "{post-id}" })) + "]]>";
            adminUrlNode.InnerXml = "<![CDATA[" + baseUrl +
                (web.IsRoot ?
                Url.Action("Index", "Sys", new { Area = "" }) :
                 Url.RouteUrl("dna_mysite", new { website = web.Owner.ToLower(), action = "Console", controller = "Account", Area = "" })) + "]]>";
            webLayoutNode.Attributes["src"].Value = Url.Action("WebLayout", "Article", new { Area = "Publishing", website = web.Name, id = 0 });
            webPreviewNode.Attributes["src"].Value = Url.Action("WebPreview", "Article", new { Area = "Publishing", website = web.Name, id = 0 });

            return Content(xmlDoc.OuterXml, "text/xml");
        }

        public ActionResult Trackback(int id)
        {
            var article =pubContext.Articles.Find(id);
            
            //this.CurrentWeb().FindArticle(id);

            if (article != null)
                return Redirect(new ArticleWrapper(article).PermaLink);

            return HttpNotFound();
        }

        private bool TestSourceUrl(Uri source, Uri mustHaveThisLink)
        {
            try
            {
                using (var client = new WebClient())
                {
                    client.Credentials = CredentialCache.DefaultNetworkCredentials;
                    var html = client.DownloadString(source);
                    return html.ToUpperInvariant().Contains(mustHaveThisLink.ToString().ToUpperInvariant());
                }
            }
            catch
            {
                return false;
            }
        }

        [HttpPost]
        public ActionResult Trackback(int id, string blog_name, string title, Uri url, string excerpt)
        {
            if (url == null)
                return Content("<?xml version=\"1.0\" encoding=\"iso-8859-1\"?><response><error>Invalid url parameter</error></response>", "text/xml");

            var article = pubContext.Articles.Find(id);
            var web = _context.Web;
            var localUrl =new Uri( UrlResolver.Resolve(HttpContext,web));

            if (article == null)
                return Content("<?xml version=\"1.0\" encoding=\"iso-8859-1\"?><response><error>The target entity is not exists.</error></response>", "text/xml");

            if (url.Authority.Equals(localUrl.Authority, StringComparison.OrdinalIgnoreCase))
            {
                var related = pubContext.Articles.Find(localUrl); 

                if (related != null)
                {
                    var relID = related.ID;

                    if (!string.IsNullOrEmpty(article.RelatedPosts))
                    {
                        var ids = article.RelatedPosts.Split(',').Select(_id => int.Parse(_id)).ToArray();

                        if (!ids.Contains(relID))
                            article.RelatedPosts += "," + relID;
                    }
                    else
                        article.RelatedPosts = relID.ToString();
                    
                    pubContext.Articles.Update(article);
                    pubContext.SaveChanges();

                    return Content("<?xml version=\"1.0\" encoding=\"iso-8859-1\"?><response><error>0</error></response>", "text/xml");
                }
            }

            if (!HttpContext.Request.Url.Host.Equals(url.Host, StringComparison.OrdinalIgnoreCase))
            {
                bool isSpammer = TestSourceUrl(url, new Uri(new ArticleWrapper(article).TrackbackUrl));
                if (isSpammer)
                    return Content("<?xml version=\"1.0\" encoding=\"iso-8859-1\"?><response><error>The source URI does not contain a link to the target URI, and so cannot be used as a source</error></response>", "text/xml");
            }

            if (!article.AllowComments)
            {
                Response.StatusCode = 404;
                return Content("<?xml version=\"1.0\" encoding=\"iso-8859-1\"?><response><error>Content not found.</error></response>", "text/xml");
            }

            var comments = article.Comments;
            
            if (comments.Count > 0)
            {
                var _exists = comments.Where(c => c.IsTrackback)
                                                  .FirstOrDefault(c => c.WebSite.Equals(url.ToString(), StringComparison.OrdinalIgnoreCase));
                if (_exists != null)
                    return Content("<?xml version=\"1.0\" encoding=\"iso-8859-1\"?><response><error>Trackback already registered</error></response>", "text/xml");
            }

           // article.AddTrackbackComment(blog_name, title, url, excerpt, HttpContext.Request.UserHostAddress);
            var comm = new Comment()
           {
               Title = title,
               Body = Server.HtmlEncode(excerpt),
               IP = Request.UserHostAddress,
               Posted = DateTime.Now,
               UserName = blog_name,
               WebSite = url.ToString(),
               IsTrackback = true,
               IsPingback = false,
           };

            if (Request.UrlReferrer != null)
                comm.UrlReferrer = Request.UrlReferrer.ToString();

            pubContext.Comments.Create(comm);
            pubContext.SaveChanges();

            new NewCommentEvent(comm).Raise(HttpContext);

            //Returns what?
            return Content("<?xml version=\"1.0\" encoding=\"iso-8859-1\"?><response><error>0</error></response>", "text/xml");
        }

        
    }

}